package com.cwz.core.captcha.core;

import com.cwz.core.captcha.support.CaptchaType;
import com.cwz.core.captcha.thirdparty.AnimationEncoder;

import java.awt.*;
import java.awt.geom.CubicCurve2D;
import java.awt.image.BufferedImage;
import java.io.OutputStream;

/**
 * @program: w-demo
 * @description: 动态验证码生成
 * @author: Wen
 **/
public class AnimCaptcha extends AbstractCaptcha {
	@Override
	public void render(OutputStream out) {
		char[] codes = this.text();
		Color[] colors = new Color[this.length];

		for(int i = 0; i < this.length; ++i) {
			colors[i] = this.color();
		}

		int x1 = 5;
		int y1 = nextInt(5, this.height / 2);
		int x2 = this.width - 5;
		int y2 = nextInt(this.height / 2, this.height - 5);
		int ctrlX = nextInt(this.width / 4, this.width / 4 * 3);
		int ctrlY = nextInt(5, this.height - 5);
		int ctrlX1;
		if (nextInt(2) == 0) {
			ctrlX1 = y1;
			y1 = y2;
			y2 = ctrlX1;
		}

		ctrlX1 = nextInt(this.width / 4, this.width / 4 * 3);
		int ctrlY1 = nextInt(5, this.height - 5);
		int[][] bezier = new int[][]{{x1, y1}, {ctrlX, ctrlY}, {ctrlX1, ctrlY1}, {x2, y2}};
		AnimationEncoder animation = new AnimationEncoder();
		animation.setQuality(180);
		animation.setDelay(100);
		animation.setRepeat(0);
		animation.start(out);

		for(int i = 0; i < this.length; ++i) {
			BufferedImage img = this.drawImage(colors, codes, i, bezier);
			animation.addFrame(img);
			img.flush();
		}

		animation.finish();
	}

	@Override
	public String toBase64() {
		return this.toBase64("data:image/png;base64,");
	}

	public BufferedImage drawImage(Color[] colors, char[] chars, int index, int[][] bezier) {
		BufferedImage image = new BufferedImage(this.width, this.height, 4);
		Graphics2D g = (Graphics2D)image.getGraphics();
		g.setColor(Color.WHITE);
		g.fillRect(0, 0, this.width, this.height);
		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g.setComposite(AlphaComposite.getInstance(3, 0.1F * (float)nextInt(10)));
		this.drawOval(g);
		this.drawLine(g);
		g.setComposite(AlphaComposite.getInstance(3, 0.1F * (float)nextInt(10)));
		g.setStroke(new BasicStroke(1.2F, 0, 2));
		g.setColor(colors[0]);
		CubicCurve2D shape = new CubicCurve2D.Double((double)bezier[0][0], (double)bezier[0][1], (double)bezier[1][0], (double)bezier[1][1], (double)bezier[2][0], (double)bezier[2][1], (double)bezier[3][0], (double)bezier[3][1]);
		g.draw(shape);
		g.setFont(this.getFont());
		FontMetrics fontMetrics = g.getFontMetrics();
		int fw = this.width / chars.length - 2;
		int fm = (fw - (int)fontMetrics.getStringBounds("W", g).getWidth()) / 2;

		for(int i = 0; i < chars.length; ++i) {
			AlphaComposite alpha = AlphaComposite.getInstance(3, this.getAlpha(index, i));
			g.setComposite(alpha);
			g.setColor(colors[i]);
			int fY = this.height - (this.height - (int)fontMetrics.getStringBounds(String.valueOf(chars[i]), g).getHeight() >> 1);
			g.drawString(String.valueOf(chars[i]), i * fw + fm + 3, fY - 3);
		}

		g.dispose();
		return image;
	}

	private float getAlpha(int i, int j) {
		int num = i + j;
		float r = 1.0F / (float)(this.length - 1);
		float s = (float)this.length * r;
		return num >= this.length ? (float)num * r - s : (float)num * r;
	}

	public AnimCaptcha() {
	}

	public AnimCaptcha(int width, int height) {
		this();
		this.setWidth(width);
		this.setHeight(height);
	}

	public AnimCaptcha(int width, int height, int length) {
		this(width, height);
		this.setLength(length);
	}

	public AnimCaptcha(int width, int height, CaptchaType type) {
		this(width, height);
		this.setType(type);
	}

	public AnimCaptcha(int width, int height, CaptchaType type, int length) {
		this(width, height, type);
		this.setLength(length);
	}

	public AnimCaptcha(int width, int height, CaptchaType type, Font font) {
		this(width, height, type);
		this.setFont(font);
	}

	public AnimCaptcha(int width, int height, CaptchaType type, Font font, int length) {
		this(width, height, type, font);
		this.setLength(length);
	}
}
